package main

import (
    "context"
    "fmt"
    "go.etcd.io/etcd/clientv3"
    "time"
    "log"
)

func main() {
    config := clientv3.Config{
        Endpoints:   []string{"fulnero.com:2379"},
        DialTimeout: 5 * time.Second,
    }
    client, err := clientv3.New(config)
    if nil != err {
        fmt.Print(err)
    }
    lease := clientv3.NewLease(client)
    leaseResp, err := lease.Grant(context.TODO(), 10)
    if nil != err {
        fmt.Println(err)
    }
    leaseID := leaseResp.ID
    ctx, cancelFunc := context.WithCancel(context.TODO())

    //两个defer用于释放锁
    defer cancelFunc()
    defer lease.Revoke(context.TODO(), leaseID)
    
    //抢锁和占用期间，需要不停的续租，续租方法返回一个只读的channel
    keepChan, err := lease.KeepAlive(ctx, leaseID)
    if nil != err {
        fmt.Println(err)
    }
    //处理续租返回的信息
    go func() {
        for {
            select {
            case keepResp := <-keepChan:
                if keepChan == nil {
                    fmt.Println("lease out")
                    goto END
                } else {
                    log.Println("get resp", keepResp.ID)
                }
            }
        }
    END:
    }()
    kv := clientv3.NewKV(client)
    txn := kv.Txn(context.TODO())
    //开始抢锁事务操作
    txn.If(clientv3.Compare(clientv3.CreateRevision("/lock/9"), "=", 0)).Then(clientv3.OpPut("/lock/9", "", clientv3.WithLease(leaseID))).Else(clientv3.OpGet("/lock/9"))
    //提交事务
    txnResp, err := txn.Commit()
    
    if nil != err {
        fmt.Println(err)
        return
    }
    //如果抢锁成功
    if txnResp.Succeeded {
        fmt.Println("success")
    } else {
        fmt.Println("fail")
    }
    time.Sleep(1 * time.Second)
    
    txn = kv.Txn(context.TODO())
    getResp, err := txn.Then(clientv3.OpGet("/lock/9")).Commit()
    if nil != err {
    	fmt.Println(err)
        return
    }
    txn = kv.Txn(context.TODO())
    txn.If(clientv3.Compare(clientv3.ModRevision("/lock/9"), "=", getResp.Header.Revision)).Then(clientv3.OpPut("/lock/9", "1", clientv3.WithLease(leaseID))).Else(clientv3.OpGet("/lock/9"))
    //提交事务
    txnResp, err = txn.Commit()
    
    if nil != err {
        fmt.Println(err)
        return
    }
    //如果抢锁成功
    if txnResp.Succeeded {
        fmt.Println("success")
    } else {
        fmt.Println("fail")
    }
    
    
    if getResp, err := kv.Get(context.TODO(), "/lock/9"); err != nil {
      log.Println(err)
   } else {
      //打印出来的create_revision是创建版本,mod_revision是修改版本, version是修改的次数
      log.Println(getResp.Kvs)
   }
   time.Sleep(1 * time.Second)
    txn = kv.Txn(context.TODO())
    txn.If(clientv3.Compare(clientv3.ModRevision("/lock/9"), "=", getResp.Header.Revision)).Then(clientv3.OpPut("/lock/9", "2", clientv3.WithLease(leaseID))).Else(clientv3.OpGet("/lock/9"))
    //提交事务
    txnResp, err = txn.Commit()
    
    if nil != err {
        fmt.Println(err)
        return
    }
    //如果抢锁成功
    if txnResp.Succeeded {
        fmt.Println("success")
    } else {
    	fmt.Println("fail")
    	fmt.Printf("%s : %s\n", txnResp.Responses[0].GetResponseRange().Kvs[0].Key, txnResp.Responses[0].GetResponseRange().Kvs[0].Value)
        fmt.Println(string(txnResp.Responses[0].GetResponseRange().Kvs[0].Value))
    }
    op := clientv3.OpGet("/lock/9")
    if opr, err := client.Do(context.TODO(), op); err != nil {
        log.Fatal(err)
    } else {
    	log.Println(opr.Get().Kvs)
    }
}
